package cc.rboot.tracking.aspect;

import cc.rboot._core.helper.AnnotationHelper;
import cc.rboot._core.helper.MethodHelper;
import cc.rboot._core.helper.OSHelper;
import cc.rboot._core.holder.AppContextHolder;
import cc.rboot.token.core.ITokenAware;
import cc.rboot.tracking.annotation.Tracking;
import cc.rboot.tracking.async.TrackingAsyncService;
import cc.rboot.tracking.core.ITrackingProcessor;
import cc.rboot.tracking.domain.TrackingRecord;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class TrackingAspect {

    @Resource
    ITokenAware tokenAware;

    @Resource
    TrackingAsyncService trackingAsyncService;

    @Pointcut("@annotation(cc.rboot.tracking.annotation.Tracking)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Tracking tracking = AnnotationHelper.get(joinPoint, Tracking.class);

        String name = tracking.name();
        if (!StringUtils.hasText(name)) {
            Method targetMethod = MethodHelper.get(joinPoint);
            name = targetMethod.toGenericString();
        }

        TrackingRecord trackingRecord = new TrackingRecord();
        trackingRecord.setName(name);
        trackingRecord.setToken(tokenAware.get());
        trackingRecord.setTime(LocalDateTime.now());
        trackingRecord.setOs(OSHelper.os());
        trackingRecord.setVersion(OSHelper.version());
        trackingRecord.setProductVersion(OSHelper.productVersion());

        Long begin = System.nanoTime();
        try {
            Object result = joinPoint.proceed();
            trackingRecord.setSuccess(true);
            return result;
        } catch (Exception ex) {
            trackingRecord.setSuccess(false);
            return ex;
        } finally {
            Long end = System.nanoTime();
            Long duration = (end - begin) / 1000000;
            trackingRecord.setDuration(duration);

            ITrackingProcessor processor = AppContextHolder.getBean(tracking.processor());
            trackingAsyncService.tracking(processor, trackingRecord);
        }
    }
}
